#include "mytcpsocket.h"
#include "mytcpserver.h"


MyTcpSocket::MyTcpSocket()
{
    //自己的readyRead信号, 处理自己的recvMsg
    connect(this, SIGNAL(readyRead()), this, SLOT(recvMsg()));

    //关联用户下线槽函数
    connect(this, SIGNAL(disconnected()), this, SLOT(clientOffLine()));
}

QString MyTcpSocket::getName()
{
    return m_strName;
}

void MyTcpSocket::recvMsg()
{
    //接收数据, 当前可读的消息有多少
    qcout << this->bytesAvailable();

    uint uiPDULen = 0;
    this->read((char*)&uiPDULen, sizeof(uint));//先接收数据总长度, 最前面的四个字节, 后面数据在后面接收

    //实际消息的长度, 最后一个参数的大小
    uint uiMsgLen = uiPDULen - sizeof(PDU);

    //申请一个空间来存储接收的消息
    PDU* pdu = mkPDU(uiMsgLen);
    //再次接收后面的数据, 接收数据的时候先偏移出开始接收的四个字节的总数据的位置
    this->read((char*)pdu+sizeof(uint), uiPDULen - sizeof(uint));

    //根据消息类型, 选择操作
    switch(pdu->uiMsgType)
    {
    case ENUM_MSG_TYPE_REGIST_REQUEST:
    {
        qcout<< "客户端注册";
        //用户注册
        handleRegist_tcpsocket(pdu);
        break;
    }
    case ENUM_MSG_TYPE_LOGIN_REQUEST:
    {
        qcout<< "客户端登录";
        //用户登录
        handleLogin_tcpsocket(pdu);
        break;
    }
    case ENUM_MSG_TYPE_ALL_ONLINE_REQUEST:
    {
        qcout<< "客户端查看所有在线用户";
        //查看所有在线用户
        handleAllOnline_tcpsocket(pdu);
        break;
    }
    case ENUM_MSG_TYPE_SEARCH_USR_REQUEST:
    {
        qcout<< "客户端搜索用户";
        //搜索用户
        handleSearch_tcpsocket(pdu);
        break;
    }
    case ENUM_MSG_TYPE_ADD_FRIEND_REQUEST:
    {
        qcout<< "客户端请求添加好友";
        handleAddFriend_tcpsocket(pdu);
        break;
    }
    case ENUM_ADDFRIEND_TYPE_NOTIFY:
    {
        qcout << "被要求的客户端回复是否添加好友";
        handleAddFriendRequest_tcpsocket(pdu);
    }

    default:
        break;

    }



    //测试输出
    qcout << "pdu->uiMsgType : " << pdu->uiMsgType;
    qcout << "pdu->caMsg : " << (char*)pdu->caMsg ;


    free(pdu);
    pdu=NULL;
}

//槽函数, 用来处理客户端下线
void MyTcpSocket::clientOffLine()
{
    handleOffLine_tcpsocket(m_strName);
}


//ENUM_MSG_TYPE_REGIST_REQUEST
void MyTcpSocket::handleRegist_tcpsocket(const PDU* pdu)
{
    //接收用户名和密码
    char caName[32] = {'\0'};
    char caPwd[32] = {'\0'};
    strncpy(caName, pdu->caData, 32);//从接收的数据中提取前32个字符给caName, 这个作为用户名
    strncpy(caPwd, pdu->caData+32, 32);//从接收的数据中提取后32个字符给caName, 这个作为密码
    //操作数据库
    bool ret = OpeDB::getInstance().handleRegist(QString(caName), QString(caPwd));
    //数据库操作成功, 向客户端返回插入数据成功
    PDU* respdu = mkPDU(0);//不需要额外空间
    respdu->uiMsgType = ENUM_MSG_TYPE_REGIST_RESPOND;//消息类型是返回
    if(ret)
    {
        strcpy(respdu->caData, REGIST_OK);
    }
    else
    {
        strcpy(respdu->caData, REGIST_FAILED);
    }
    //给客户端发送回去
    write((char*)respdu, respdu->uiPDULen);
    free(respdu);
    respdu = NULL;

}

//服务器处理登录请求
void MyTcpSocket::handleLogin_tcpsocket(const PDU *pdu)
{
    //接收用户名和密码
    char caName[32] = {'\0'};
    char caPwd[32] = {'\0'};
    strncpy(caName, pdu->caData, 32);//从接收的数据中提取前32个字符给caName, 这个作为用户名
    strncpy(caPwd, pdu->caData+32, 32);//从接收的数据中提取后32个字符给caName, 这个作为密码
    //操作数据库
    int ret = OpeDB::getInstance().handleLogin(QString(caName), QString(caPwd));
    //数据库查询成功, 向客户端返回插入数据成功
    PDU* respdu = mkPDU(0);//不需要额外空间
    respdu->uiMsgType = ENUM_MSG_TYPE_LOGIN_RESPOND;//消息类型是返回

    //返回状态码
    respdu->caData[0] = ret;
    qcout << "返回码 ret = " << ret;

    m_strName = QString(caName);//存储用户名

    //给客户端发送回去
    write((char*)respdu, respdu->uiPDULen);

    //释放空间
    free(respdu);
    respdu = NULL;


}


//用户下线
void MyTcpSocket::handleOffLine_tcpsocket(QString m_name)
{
    bool ret = OpeDB::getInstance().handleOffLine(m_name);


    if(ret)
    {
        qcout << "用户" << m_name << "已经下线";
        emit offline(this);//给MyTcpServer发送客户端下线信号, 让MyTcpServer在QList中删除socket
    }
    else
    {
        qcout << "用户" << m_name << "未能下线";
    }
}

//查看所有在线用户
void MyTcpSocket::handleAllOnline_tcpsocket(const PDU *pdu)
{
    qcout << "用户发来了请求, 要查看所有在线用户";
    qcout << "查看所有用户消息长度" << pdu->uiMsgLen;
    QStringList usrlist = OpeDB::getInstance().handleAllOnline();//从数据库返回得到用户列表
    //获取到QStringList, 放到PDU中, 发送给客户端
    uint uiMsgLen = (usrlist.size()*32);
    PDU* respdu = mkPDU(uiMsgLen);
    respdu->uiMsgType = ENUM_MSG_TYPE_ALL_ONLINE_RESPOND;//消息返回类型是回复所有在线用户
    for(int i = 0; i<usrlist.size();i++)
    {
        memcpy((char*)(respdu->caMsg)+i*32, usrlist.at(i).toStdString().c_str(), usrlist.at(i).size());
    }

    //给客户端发送回去
    write((char*)respdu, respdu->uiPDULen);

    //释放空间
    free(respdu);
    respdu = NULL;

}

//搜索用户
void MyTcpSocket::handleSearch_tcpsocket(const PDU *pdu)
{
    qcout << "用户发来了请求, 要搜索用户";
    //接收用户名
    char caName[32] = {'\0'};
    strncpy(caName, pdu->caData, 32);//从接收的数据中提取前32个字符给caName, 这个作为用户名
    //操作数据库
    int ret = OpeDB::getInstance().handleSearchUsr(QString(caName));
    //数据库查询成功, 向客户端返回插入数据成功
    PDU* respdu = mkPDU(0);//不需要额外空间
    respdu->uiMsgType = ENUM_MSG_TYPE_SEARCH_USR_RESPOND;//消息类型是返回
    //返回状态码
    respdu->caData[0] = ret;
    qcout << "返回码 ret = " << ret;
    //给客户端发送回去
    write((char*)respdu, respdu->uiPDULen);
    //释放空间
    free(respdu);
    respdu = NULL;

}

//添加好友
void MyTcpSocket::handleAddFriend_tcpsocket(const PDU *pdu)
{
    qcout << "用户发来了请求, 要添加好友";
    //接收用户名
    char firstName[32] = {'\0'};
    char secondName[32] = {'\0'};


    strncpy(firstName, pdu->caData, 32);//从接收的数据中提取前32个字符给caName, 这个作为客户端
    strncpy(secondName, pdu->caData+32, 32);//从接收的数据中提取前32个字符给caName, 这个作为要加的用户名

    QString fName = QString(firstName);
    QString sName = QString(secondName);

    qcout<< "服务器在数据库中查询关系中...";
    int ret = OpeDB::getInstance().handleAddFriend(fName, sName);
    qcout << "服务器查询完毕";

    //返回值结果
    //  return ENUM_ADDFRIEND_TYPE_EMPTY;//用户名或密码为空
    //  return ENUM_ADDFRIEND_TYPE_ALWAYS;//查询到结果表明两个人已经是好友了
    //  return ENUM_SEARCH_OFFLINE_TYPE;//两一个人暂时不在线, 暂时不能添加好友
    //  return ENUM_ADDFRIEND_TYPE_SUCCESS;//可以添加好友
    qcout << "服务器查询两个人的关系" << ret;
    qcout << "ENUM_ADDFRIEND_TYPE_SUCCESS = " << ENUM_ADDFRIEND_TYPE_SUCCESS;
    if(ENUM_ADDFRIEND_TYPE_SUCCESS == ret)
    {
        qcout<< "开始查找对方";
        //如果可以成为好友, 那么服务器就向对方转发有要加好友的消息
        PDU* resFpdu = mkPDU(0);//不需要额外空间
        resFpdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_REQUEST_WAIT;//等待添加好友
        strncpy(resFpdu->caData, fName.toStdString().c_str(), fName.size());//用户名
        //strncpy(firstName, pdu->caData, 32);//请求方
        qcout<< "-----------" << fName;
        QList<MyTcpSocket*> m_tcpSocketList = MyTcpServer::getInstance().get_m_tcpSocketList();
        for(int i = 0; i<m_tcpSocketList.size(); i++)
        {
            if(m_tcpSocketList.at(i)->getName() == sName)
            {
                qcout << "找到了对方";
                //通过名字找到对应的socket
                //给对方客户端发送回去
                qcout << "对方的名字sName = "<< sName;
                m_tcpSocketList.at(i)->write((char*)resFpdu, resFpdu->uiPDULen);
                break;//退出查找操作
            }
        }


        //释放空间
        free(resFpdu);
        resFpdu = NULL;
    }

    //再给请求方发等待回复的消息
    PDU* respdu = mkPDU(0);//不需要额外空间
    respdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_RESPOND;//添加好友返回
    //返回状态码
    respdu->caData[0] = ret;
    qcout << "返回码 ret = " << ret;
    //给客户端发送回去
    write((char*)respdu, respdu->uiPDULen);
    //释放空间
    free(respdu);
    respdu = NULL;

}

//被邀请的客户端的回复
void MyTcpSocket::handleAddFriendRequest_tcpsocket(const PDU *pdu)
{
    qcout<< "回复说什么了呢";
    //接收用户名
    char firstName[32] = {'\0'};
    char secondName[32] = {'\0'};

    strncpy(firstName, pdu->caData, 32);//从接收的数据中提取前32个字符给caName, 这个作为客户端
    strncpy(secondName, pdu->caData+32, 32);//从接收的数据中提取前32个字符给caName, 这个作为要加的用户名

    QString fName = QString(firstName);
    QString sName = QString(secondName);

    qcout<< "请求者: " << fName;
    qcout << "被邀请者 : " << sName;

    PDU* resPdu = mkPDU(1);
    strncpy(resPdu->caData, pdu->caData, 32);
    strncpy(resPdu->caData+32, pdu->caData+32, 32);


    //从m_tcpSocketList中把请求方的socket找到
    MyTcpSocket* fSocket = NULL;
    QList<MyTcpSocket*> m_tcpSocketList = MyTcpServer::getInstance().get_m_tcpSocketList();
    for(int i = 0; i<m_tcpSocketList.size(); i++)
    {
        if(m_tcpSocketList.at(i)->getName() == fName)
        {
            qcout << "服务器回复被拒绝的消息时找到了请求方" << fName;
            //通过名字找到对应的socket
            //给对方客户端发送回去
            qcout << "提出拒绝的人的名字是 sName = "<< sName;
            //m_tcpSocketList.at(i)->write((char*)resPdu, resPdu->uiPDULen);
            fSocket = m_tcpSocketList.at(i);
            break;//退出查找操作
        }
    }

    if(pdu->caMsg[0] == ENUM_ADDFRIEND_TYPE_AGREE)
    {
        //同意加好友
        qcout << "服务器收到被邀请方同意的回复";
        qcout<< "服务器收到 pdu->caData[0]" << pdu->caMsg[0];

        resPdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_RESPOND_AGREE;//回复同意
        //第一先给客户端发送可以添加好友
        fSocket->write((char*)resPdu, resPdu->uiPDULen);

        //第二给服务器的friend表插入两个用户是好友的数据字段


    }
    else if(pdu->caMsg[0] == ENUM_ADDFRIEND_TYPE_REFUSE)
    {
        //不同意加好友
        resPdu->uiMsgType = ENUM_MSG_TYPE_ADD_FRIEND_RESPOND_REFUSE;//回复拒绝
        qcout << "服务器收到拒绝的回复";
        qcout<< "服务器收到 pdu->caData[0]" << pdu->caMsg[0];

        //给客户端发送, 对方拒绝加好友
        fSocket->write((char*)resPdu, resPdu->uiPDULen);

    }
    else
    {
        //错误
        qcout << "ENUM_ADDFRIEND_TYPE_REFUSE" << ENUM_ADDFRIEND_TYPE_REFUSE;
        qcout << "ENUM_ADDFRIEND_TYPE_AGREE" << ENUM_ADDFRIEND_TYPE_AGREE;
        qcout<< "服务器收到错误的回复 pdu->caData[0]" << pdu->caMsg[0];
    }

    free(resPdu);
    resPdu = NULL;


}
